﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace SHomeWorkshop.LunarConcept
{
    /// <summary>
    /// FormatFillBlankTextWindow.xaml 的交互逻辑
    /// </summary>
    public partial class FormatFillBlankTextWindow : Window
    {
        public FormatFillBlankTextWindow()
        {
            InitializeComponent();
        }

        private void btnInsertBrackets_Click(object sender, RoutedEventArgs e)
        {
            TextRange sel = mRtb.Selection;
            if (sel.Text.Length <= 0)
            {
                //sel.End.GetInsertionPosition(LogicalDirection.Forward).InsertTextInRun("【】");
                sel.Text = "【】";
                TextPointer middlePt = sel.Start.GetPositionAtOffset(1, LogicalDirection.Forward);
                sel.Select(middlePt, middlePt);
            }
            else
            {
                sel.End.InsertTextInRun("】");
                sel.Start.InsertTextInRun("【");
            }
        }

        private bool ValidatePairOfBrackets(Paragraph paragraph, StringBuilder errorMsg = null)
        {
            if (paragraph == null) return false;

            List<int> startBracketIndexesList = new List<int>();
            List<int> endBracketIndexesList = new List<int>();

            StringBuilder sb = new StringBuilder();
            foreach (Inline inline in paragraph.Inlines)
            {
                Run run = inline as Run;
                if (run == null) continue;

                sb.Append(run.Text);
            }

            string text = sb.ToString();
            for (int i = 0; i < text.Length; i++)
            {
                char c = text[i];
                if (c == '【')
                {
                    startBracketIndexesList.Add(i);
                }
                else if (c == '】')
                {
                    endBracketIndexesList.Add(i);
                }
            }

            #region 对两个列表比较之前，先保证两个列表成员数目相等。
            if (startBracketIndexesList.Count < endBracketIndexesList.Count)
            {
                for (int i = 0; i < (endBracketIndexesList.Count - startBracketIndexesList.Count); i++)
                {
                    startBracketIndexesList.Add(-1);
                }

                if (errorMsg != null)
                    errorMsg.Append("括弧数目不等。\r\n");
            }
            else if (startBracketIndexesList.Count > endBracketIndexesList.Count)
            {
                for (int i = 0; i < (startBracketIndexesList.Count - endBracketIndexesList.Count); i++)
                {
                    endBracketIndexesList.Add(-1);
                }

                if (errorMsg != null)
                    errorMsg.Append("括弧数目不等。\r\n");
            }
            #endregion

            paragraph.Background = Brushes.Transparent;

            for (int i = 0; i < startBracketIndexesList.Count; i++)
            {
                if (startBracketIndexesList[i] == -1 || endBracketIndexesList[i] == -1)
                {
                    return false;
                }

                if (startBracketIndexesList[i] >= endBracketIndexesList[i])
                {
                    return false;
                }

                if (startBracketIndexesList[i] + 1 == endBracketIndexesList[i])
                {
                    //首尾括弧之间没有答案文本
                    if (errorMsg != null)
                        errorMsg.Append("首尾括弧之间没有答案文本。\r\n");
                    return false;
                }
            }

            for (int i = 0; i < startBracketIndexesList.Count - 1; i++)
            {
                //前一个尾括弧必须在后一个首括弧之前
                if (endBracketIndexesList[i] >= startBracketIndexesList[i + 1])
                {
                    if (errorMsg != null)
                        errorMsg.Append("括弧对交错。\r\n");
                    return false;
                }

                if (endBracketIndexesList[i] + 1 == startBracketIndexesList[i + 1])
                {
                    //前一个尾括弧正好在后一个首括弧前1位——两个填空没必要连在一起——这时候做成一个填空就可以了。
                    if (errorMsg != null)
                        errorMsg.Append("两个填充项连在一起，这没必要。\r\n");
                    return false;
                }
            }

            return true;
        }

        private void btnValidateBrackets_Click(object sender, RoutedEventArgs e)
        {
            TextRange sel = mRtb.Selection;
            if (sel == null || sel.Start.Paragraph == null) return;

            sel.Start.Paragraph.Background = Brushes.Transparent;

            StringBuilder errorMsg = new StringBuilder();

            bool vResult = ValidatePairOfBrackets(sel.Start.Paragraph, errorMsg);

            if (vResult == false)
            {
                sel.Start.Paragraph.Background = Brushes.Yellow;
            }

            if (vResult == false && errorMsg.Length > 0)
            {
                LunarMessage.Warning("本段配对存在如下问题：\r\n=====================\r\n" + errorMsg.ToString());
                return;
            }
        }

        private void btnBuildFillBlands_Click(object sender, RoutedEventArgs e)
        {
            bool hasErrors = false;

            foreach (Block b in mDoc.Blocks)
            {
                Paragraph p = b as Paragraph;
                if (p != null)
                {
                    if (ValidatePairOfBrackets(p) == false)
                    {
                        hasErrors = true;
                        p.Background = Brushes.Yellow;
                    }
                    else
                    {
                        p.Background = Brushes.Transparent;
                    }
                }
            }

            if (hasErrors)
            {
                LunarMessage.Warning("部分段落的括弧配对有问题，请检查以黄色背景显示的段落。根据请况，可能需要检查不止一次。");
                return;
            }

            StringBuilder sumFillBlankSb = new StringBuilder();
            StringBuilder sumAnswerSb = new StringBuilder();

            int paragraphIndex = 0;
            int blankIndex = 0;

            foreach (Block b in mDoc.Blocks)
            {
                StringBuilder fillBlankSb = new StringBuilder();
                StringBuilder answerSb = new StringBuilder();
                Paragraph p = b as Paragraph;
                if (p == null) continue;


                int blankCountInParagraph = BuildParagraphFillBlank(p, ref fillBlankSb, ref answerSb, blankIndex);
                if (blankCountInParagraph < 0)
                {
                    hasErrors = true;
                }
                else
                {
                    blankIndex += blankCountInParagraph;
                }

                if (blankCountInParagraph > 0)//空段落不算序号。
                {
                    paragraphIndex++;
                    sumFillBlankSb.Append(paragraphIndex.ToString() + ".");
                    sumAnswerSb.Append(paragraphIndex.ToString() + ".");
                }

                sumFillBlankSb.Append(fillBlankSb);
                sumFillBlankSb.Append("\r\n");

                sumAnswerSb.Append(answerSb);
                sumAnswerSb.Append("\r\n");
            }

            sumFillBlankSb.Append("\r\n========答========案========\r\n");
            sumFillBlankSb.Append(sumAnswerSb);

            Clipboard.SetData(DataFormats.UnicodeText, sumFillBlankSb.ToString());

            if (hasErrors)
            {
                LunarMessage.Warning("在生成过程中可能存在错误！");
            }
            else
            {
                LunarMessage.Warning("已生成带序号的填充文本，并已复制到剪贴板！");
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="p"></param>
        /// <param name="fillBlankSb"></param>
        /// <param name="answerSb"></param>
        /// <param name="blankIndex">表示到前一段为止，已经存在多少个填充项。</param>
        /// <returns></returns>
        private int BuildParagraphFillBlank(Paragraph p, ref StringBuilder fillBlankSb, ref StringBuilder answerSb, int blankIndex)
        {
            StringBuilder sb = new StringBuilder();

            foreach (Inline inline in p.Inlines)
            {
                Run r = inline as Run;
                if (r != null)
                {
                    sb.Append(r.Text);
                }
            }

            List<int> startBracketIndexesList = new List<int>();
            List<int> endBracketIndexesList = new List<int>();

            string text = sb.ToString();
            for (int i = 0; i < text.Length; i++)
            {
                char c = text[i];
                if (c == '【')
                {
                    startBracketIndexesList.Add(i);
                }
                else if (c == '】')
                {
                    endBracketIndexesList.Add(i);
                }
            }

            if (startBracketIndexesList.Count != endBracketIndexesList.Count)
            {
                LunarMessage.Warning("发生意外，通过校验后，首尾括弧的两个索引列表数目竟然不一样，无法继续。");
                return -1;
            }

            //先提取出答案
            //再替换掉所有括弧对之间的文本。——替换要用逆序！！！
            for (int i = startBracketIndexesList.Count - 1; i >= 0; i--)
            {
                string answerText = text.Substring(startBracketIndexesList[i] + 1,
                    endBracketIndexesList[i] - startBracketIndexesList[i] - 1);
                answerSb.Insert(0, "[" + (blankIndex + i + 1).ToString() + "]" + answerText + "\t");

                string tailText;

                if (i == startBracketIndexesList.Count - 1)
                {
                    tailText = text.Substring(endBracketIndexesList[i] + 1);
                }
                else
                {
                    tailText = text.Substring(endBracketIndexesList[i] + 1,
                        startBracketIndexesList[i + 1] - endBracketIndexesList[i] - 1);
                }

                fillBlankSb.Insert(0, tailText);
                fillBlankSb.Insert(0, GetBlankString(answerText, blankIndex + i + 1));
            }

            if (startBracketIndexesList.Count <= 0)
            {
                //如果此段没有任何填充项。则原文本输出（注意，没有答案——因为没有填充项嘛）。
                fillBlankSb.Append(text);
                return 0;
            }

            string headerText = text.Substring(0, startBracketIndexesList[0]);
            fillBlankSb.Insert(0, headerText);

            return startBracketIndexesList.Count;
        }

        private string GetBlankString(string answer, int index)
        {
            if (answer == null || answer.Length <= 0) return "[⊙]____";
            else
            {
                int length = answer.Length;

                StringBuilder sb = new StringBuilder();
                for (int i = 0; i < length; i++)
                {
                    char c = answer[i];

                    //０是65296；１是65297。——这与半角英文数字不同。
                    //半角的英文数字序列是（1,2,3...,8,9,0）。

                    //全角字母，大写：Ａ是65313；Ｚ是65338。
                    //全角字母，小写：ａ是65345；ｚ是65370。

                    if ((c >= '1' && c <= '0') || (c >= 'ａ' && c <= 'ｚ') ||
                        (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') ||
                        (c >= '０' && c <= '９') || (c >= 'Ａ' && c <= 'Ｚ'))
                    {
                        sb.Append("_");
                    }
                    else
                    {
                        sb.Append("__");
                    }
                }

                sb.Append("__");

                return sb.Insert(0, " [" + index.ToString() + "]").ToString();
            }
        }

        private void btnHelp_Click(object sender, RoutedEventArgs e)
        {
            MessageBox.Show(
@"先编辑好填空题文本。格式如下：
①直接连答案编辑；
②每段落为一题，不要手工输入试题序号（会自动按段落生成序号）；
③——空段会被忽略；
④要做成填充项的文本，在选中后用“【”和“】”这样的括号对（用按钮较快）来包围；
⑤填充项之间不能交错，否则无法生成；
⑥填充项不能连在一起，否则也无法生成；
⑦填充项的括号必须配对；
⑧——有问题的段落，会以黄色背景显示（可以将插入点移到该段，使用“检查本段括弧配对情况”功能看看存在什么问题）。",
                   "Lunar Concept 填空题格式化工具", MessageBoxButton.OK, MessageBoxImage.Information);
        }

        private void btnAbout_Click(object sender, RoutedEventArgs e)
        {
            MessageBox.Show("杨震宇 2011年11月27日", "Lunar Concept 填空题格式化工具", MessageBoxButton.OK, MessageBoxImage.Information);
        }

        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            mRtb.AppendText(@"这是一些试验文本，准备用来格式化为填空题。
要格式化为填空项的文本需要以实心方括号包围，且方括号间必须配对并不能交叉。
这是一个【填空项】。
这行【【有】问】题
没有问题的情况下，点击上面的“生成填空”按钮即可生成填空文本（带答案）。
不需要行号，会自动生成题号、填空序号。
有问题的段落会显示为黄色背景。
");
            mRtb.SelectAll();
            mRtb.Focus();
        }

        private void mRtb_PreviewKeyUp(object sender, KeyEventArgs e)
        {
            KeyStates ksLeftCtrl = Keyboard.GetKeyStates(Key.LeftCtrl);
            KeyStates ksRightCtrl = Keyboard.GetKeyStates(Key.RightCtrl);

            bool isCtrl = false;

            if ((ksLeftCtrl & KeyStates.Down) > 0 || (ksRightCtrl & KeyStates.Down) > 0)
            {
                isCtrl = true;
            }

            if (e.Key == Key.F)
            {
                if (isCtrl)
                {
                    btnInsertBrackets_Click(sender, e);
                }
            }
            else if (e.Key == Key.F5)
            {
                btnInsertBrackets_Click(sender, e);
            }
            else if (e.Key == Key.F6)
            {
                btnBuildFillBlands_Click(sender, e);
            }
            else if (e.Key == Key.F1)
            {
                btnValidateBrackets_Click(sender, e);
            }
        }

        private void Window_PreviewKeyDown(object sender, KeyEventArgs e)
        {
            //屏蔽Ctrl+V，去除富文本格式。

            if (e.Key == Key.V)
            {
                KeyStates ksLeftCtrl = Keyboard.GetKeyStates(Key.LeftCtrl);
                KeyStates ksRightCtrl = Keyboard.GetKeyStates(Key.RightCtrl);

                bool isCtrl = false;

                if ((ksLeftCtrl & KeyStates.Down) > 0 || (ksRightCtrl & KeyStates.Down) > 0)
                {
                    isCtrl = true;
                }

                if (isCtrl)
                {
                    PasteWithoutStyle();

                    e.Handled = true;
                }
            }
        }

        private void PasteWithoutStyle()
        {
            mRtb.Selection.Text = Clipboard.GetText(TextDataFormat.Text);

            TextRange sel = mRtb.Selection;

            sel.Select(sel.End, sel.End);
        }

        private void cmiCut_Click(object sender, RoutedEventArgs e)
        {
            mRtb.Cut();
        }

        private void cmiCopy_Click(object sender, RoutedEventArgs e)
        {
            mRtb.Copy();
        }

        private void cmiPaste_Click(object sender, RoutedEventArgs e)
        {
            PasteWithoutStyle();//其实只是为了修改这个。
        }

        private void cmdSelectAll_Click(object sender, RoutedEventArgs e)
        {
            mRtb.SelectAll();
        }
    }
}
